/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.project;

import cn.ac.nercis.pes.common.event.ProcessCallback;
import cn.ac.nercis.pes.common.utils.JsonUtils;
import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.standard.*;
import cn.ac.nercis.pes.model.standard.analyze.LayerEvaluationSDTO;
import cn.ac.nercis.pes.model.standard.analyze.OverallEvaluationSDTO;
import cn.ac.nercis.pes.model.standard.analyze.ResultCorrectionSDTO;
import cn.ac.nercis.pes.model.standard.analyze.UnitEvaluationSDTO;
import cn.ac.nercis.pes.model.standard.asset.AssetSDTO;
import cn.ac.nercis.pes.model.standard.asset.PersonnelSDTO;
import cn.ac.nercis.pes.model.standard.asset.SecurityDocumentSDTO;
import cn.ac.nercis.pes.model.standard.evaluation.EvaluationRecordSDTO;
import cn.ac.nercis.pes.model.standard.planning.EvaluationDescSDTO;
import cn.ac.nercis.pes.model.standard.planning.EvaluationMethodSDTO;
import cn.ac.nercis.pes.model.standard.planning.EvaluationRequireSDTO;
import cn.ac.nercis.pes.model.standard.prepare.*;
import cn.ac.nercis.pes.model.standard.report.EvaluationReportSDTO;
import cn.ac.nercis.pes.repository.dal.evaluation.*;
import cn.ac.nercis.pes.repository.dal.project.*;
import cn.ac.nercis.pes.repository.dal.report.EvaluationReportRepository;
import cn.ac.nercis.pes.repository.mapper.standard.SystemExportMapper;
import cn.ac.nercis.pes.repository.model.project.SystemDO;
import cn.ac.nercis.pes.service.utils.DistinctUtils;
import cn.ac.nercis.pes.service.utils.FileManage;
import cn.hutool.core.io.FileUtil;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 系统数据导出服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public class SystemExportService {
    private final SystemRepository systemRepository;
    private final SystemEvaluationRepository systemEvaluationRepository;
    private final SystemTargetRepository systemTargetRepository;
    private final SystemSpecialTargetRepository systemSpecialTargetRepository;
    private final SystemProcessRepository systemProcessRepository;
    private final EvaluationProcessRepository evaluationProcessRepository;
    private final EvaluationContentRepository evaluationContentRepository;
    private final EvaluatorRepository evaluatorRepository;
    private final EvaluationToolsRepository evaluationToolsRepository;
    private final PasswordServerRepository passwordServerRepository;
    private final SecurityThreatRepository securityThreatRepository;
    private final AssetRepository assetRepository;
    private final PersonnelRepository personnelRepository;
    private final SecurityDocumentRepository securityDocumentRepository;
    private final AssetEvaluationDescRepository evaluationDescRepository;
    private final AssetEvaluationMethodRepository evaluationMethodRepository;
    private final EvaluationRequireRepository evaluationRequireRepository;
    private final EvaluationRecordRepository evaluationRecordRepository;
    private final UnitEvaluationRepository unitEvaluationRepository;
    private final LayerEvaluationRepository layerEvaluationRepository;
    private final OverallEvaluationRepository overallEvaluationRepository;
    private final ResultCorrectionRepository resultCorrectionRepository;
    private final UnitRiskAnalysisRepository riskAnalysisRepository;
    private final EvaluationReportRepository evaluationReportRepository;
    private final EvaluatorQualificationRepository evaluatorQualificationRepository;

    private ProcessCallback processCallback;

    @Autowired
    public SystemExportService(SystemRepository systemRepository,
                               SystemEvaluationRepository systemEvaluationRepository,
                               SystemTargetRepository systemTargetRepository,
                               SystemSpecialTargetRepository systemSpecialTargetRepository,
                               SystemProcessRepository systemProcessRepository,
                               EvaluationProcessRepository evaluationProcessRepository,
                               EvaluationContentRepository evaluationContentRepository,
                               EvaluatorRepository evaluatorRepository,
                               EvaluationToolsRepository evaluationToolsRepository,
                               PasswordServerRepository passwordServerRepository,
                               SecurityThreatRepository securityThreatRepository,
                               AssetRepository assetRepository,
                               PersonnelRepository personnelRepository,
                               SecurityDocumentRepository securityDocumentRepository,
                               AssetEvaluationDescRepository evaluationDescRepository,
                               AssetEvaluationMethodRepository evaluationMethodRepository,
                               EvaluationRequireRepository evaluationRequireRepository,
                               EvaluationRecordRepository evaluationRecordRepository,
                               UnitEvaluationRepository unitEvaluationRepository,
                               LayerEvaluationRepository layerEvaluationRepository,
                               OverallEvaluationRepository overallEvaluationRepository,
                               ResultCorrectionRepository resultCorrectionRepository,
                               UnitRiskAnalysisRepository riskAnalysisRepository,
                               EvaluationReportRepository evaluationReportRepository,
                               EvaluatorQualificationRepository evaluatorQualificationRepository) {
        this.systemRepository = systemRepository;
        this.systemEvaluationRepository = systemEvaluationRepository;
        this.systemTargetRepository = systemTargetRepository;
        this.systemSpecialTargetRepository = systemSpecialTargetRepository;
        this.systemProcessRepository = systemProcessRepository;
        this.evaluationProcessRepository = evaluationProcessRepository;
        this.evaluationContentRepository = evaluationContentRepository;
        this.evaluatorRepository = evaluatorRepository;
        this.evaluationToolsRepository = evaluationToolsRepository;
        this.passwordServerRepository = passwordServerRepository;
        this.securityThreatRepository = securityThreatRepository;
        this.assetRepository = assetRepository;
        this.personnelRepository = personnelRepository;
        this.securityDocumentRepository = securityDocumentRepository;
        this.evaluationDescRepository = evaluationDescRepository;
        this.evaluationMethodRepository = evaluationMethodRepository;
        this.evaluationRequireRepository = evaluationRequireRepository;
        this.evaluationRecordRepository = evaluationRecordRepository;
        this.unitEvaluationRepository = unitEvaluationRepository;
        this.layerEvaluationRepository = layerEvaluationRepository;
        this.overallEvaluationRepository = overallEvaluationRepository;
        this.resultCorrectionRepository = resultCorrectionRepository;
        this.riskAnalysisRepository = riskAnalysisRepository;
        this.evaluationReportRepository = evaluationReportRepository;
        this.evaluatorQualificationRepository = evaluatorQualificationRepository;
    }

    public void setProcessCallback(ProcessCallback callback) {
        this.processCallback = callback;
    }

    /**
     * 导出系统数据
     *
     * @param systemId   系统ID
     * @param filePath   导出文件存储路径
     * @return 导出生成结果
     */
    public Result<String> exportSystemData(@NonNull String systemId, File filePath) {
        SystemDO systemDO = systemRepository.findById(systemId).orElse(null);
        if (Objects.isNull(systemDO)) {
            return Result.failed(ResultCode.SYSTEM_NOT_EXIST);
        }
        var evaluation = systemEvaluationRepository.findBySystemId(systemId).orElse(null);
        if(Objects.isNull(evaluation)){
            return Result.failed("被测信息系统基本信息不完整！");
        }
        SystemSDTO systemSDTO = SystemExportMapper.INSTANCE.toStandardDTO(systemDO);
        systemSDTO.setEvaluation(SystemExportMapper.INSTANCE.toDTO(evaluation));
        ProjectSDTO projectSDTO = SystemExportMapper.INSTANCE.toStandardDTO(systemDO.getProject());
        ExecutorService executor = Executors.newFixedThreadPool(1);
        CompletableFuture<InputStream> compressFuture = CompletableFuture
                .supplyAsync(() -> this.compressSystemData(projectSDTO, systemSDTO), executor);
        CompletableFuture<Result<String>> encryptFuture = compressFuture
                .thenApplyAsync(is -> {
                    try {
                        var encryptResult = this.saveSystemDataFile(is,filePath);
                        if(encryptResult.isSuccess()){
                            processNotify(1, "系统数据导出完成");
                            return Result.success();
                        }else{
                            processNotify(1, "加密导出系统数据失败");
                            return encryptResult;
                        }
                    } catch (IOException e) {
                        log.error("加密导出系统数据失败：", e);
                        return Result.failed("导出系统数据进行加密处理失败");
                    }
                }, executor);
        try {
            return encryptFuture.get(5, TimeUnit.MINUTES);
        } catch (Exception ex) {
            log.error("导出系统数据错误：", ex);
            return Result.failed(ex.getMessage());
        } finally {
            executor.shutdownNow();
        }
    }

    private synchronized InputStream compressSystemData(ProjectSDTO projectSDTO, @NonNull SystemSDTO systemDO) {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(bos)) {
            generateVersionInfo(zos);
            exportProjectBaseData(projectSDTO, zos);
            exportSystemBaseData(systemDO, zos);

            File systemFileDir = FileUtils.getFile(FileManage.getSystemDir(systemDO.getId()));
            if (systemFileDir.exists()) {
                processNotify(0.2, "导出系统证据及相关文件");
                compressSystemFileData(systemFileDir, StandardInfo.SYSTEM_FILE_DIR.getValue().concat(systemFileDir.getName()),
                        zos);
            }

            exportSystemTargetData(systemDO, zos);
            exportSystemSpecialTargetData(systemDO, zos);
            exportSystemProcessData(systemDO, zos);

            exportEvaluationProcessData(systemDO, zos);
            exportEvaluationContentData(systemDO, zos);
            exportEvaluatorData(systemDO, zos);
            exportEvaluationToolData(systemDO, zos);
            exportPasswordServerData(systemDO, zos);
            exportSecurityThreatData(systemDO, zos);
            exportPersonnelData(systemDO, zos);
            exportSecurityDocumentData(systemDO, zos);
            exportAssetData(systemDO, zos);

            exportEvaluationDescData(systemDO, zos);
            exportEvaluationMethodData(systemDO, zos);
            exportEvaluationRequireData(systemDO, zos);

            exportEvaluationRecordData(systemDO, zos);

            exportUnitEvaluationData(systemDO, zos);
            exportLayerEvaluationData(systemDO, zos);
            exportOverallEvaluationData(systemDO, zos);
            exportResultCorrectionData(systemDO, zos);
            exportRiskAnalysisData(systemDO, zos);

            exportEvaluatorQualificationData(systemDO, zos);

            exportEvaluationReportData(systemDO, zos);

            processNotify(0.8, "导出系统数据压缩完成");
        } catch (Exception e) {
            log.error("导出系统数据失败：", e);
            throw new RuntimeException("导出系统数据失败", e);
        }
        return new ByteArrayInputStream(bos.toByteArray());
    }

    public static void compressSystemFileData(File target, String name, ZipOutputStream zOut) {
        try {
            if (target.isDirectory()) {
                File[] files = target.listFiles();
                if (Arrays.isNullOrEmpty(files)) {
                    zOut.putNextEntry(new ZipEntry(name.concat("/")));
                    zOut.closeEntry();
                } else {
                    for (File f : files) {
                        compressSystemFileData(f, name.concat("/").concat(f.getName()), zOut);
                    }
                }
            } else {
                zOut.putNextEntry(new ZipEntry(name));
                zOut.write(FileUtils.readFileToByteArray(target));
            }
        } catch (IOException ex) {
            throw new RuntimeException(String.format("压缩%s文件失败：", name), ex);
        }
    }

    private synchronized Result<String> saveSystemDataFile(@NonNull InputStream inputStream, File filePath) throws IOException {
        processNotify(0.9, "保存导出系统数据文件");
        FileUtil.writeFromStream(inputStream,filePath);
        return Result.success();
    }

    private void generateVersionInfo(ZipOutputStream zOut) {
        try {
            zOut.putNextEntry(new ZipEntry(StandardInfo.MANIFEST_FILE.getValue()));
            zOut.write(generateFileStreamData(JsonUtils.toJson(StandardManifestDTO.builder()
                    .version(StandardInfo.VERSION.getValue())
                    .files(StandardInfo.findManifestFiles())
                    .build())));
        } catch (IOException ex) {
            throw new RuntimeException("添加版本信息失败：", ex);
        }
    }

    private void exportProjectBaseData(ProjectSDTO projectDO, ZipOutputStream zOut) {
        processNotify(0.1, "导出系统基础数据");
        try {
            zOut.putNextEntry(new ZipEntry(StandardInfo.PROJECT_FILE.getValue()));
            zOut.write(generateFileStreamData(JsonUtils.toJson(projectDO)));
        } catch (IOException ex) {
            throw new RuntimeException("系统基础数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSystemBaseData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.1, "导出系统基础数据");
        try {
            zOut.putNextEntry(new ZipEntry(StandardInfo.SYSTEM_BASE_FILE.getValue()));
            zOut.write(generateFileStreamData(JsonUtils.toJson(systemSDTO)));
        } catch (IOException ex) {
            throw new RuntimeException("系统基础数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSystemTargetData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统指标数据");
        try {
            List<SystemTargetSDTO> targets = systemTargetRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(targets)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.SYSTEM_TARGET_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(targets)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统指标数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSystemSpecialTargetData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统特殊指标数据");
        try {
            var targets = systemSpecialTargetRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(targets)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.SYSTEM_SPECIAL_TARGET_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(targets)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统特殊指标数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSystemProcessData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统测评进度数据");
        try {
            List<SystemProcessSDTO> systemProcess = systemProcessRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customSystemProcessDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(systemProcess)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.SYSTEM_PROCESS_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(systemProcess)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评进度数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationProcessData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统测评过程数据");
        try {
            List<EvaluationProcessSDTO> data = evaluationProcessRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationProcessDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_PROCESS_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评过程数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationContentData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统测评内容数据");
        try {
            List<EvaluationContentSDTO> data = evaluationContentRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationContentDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_CONTENT_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评内容数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluatorData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统测评项目组成员数据");
        try {
            List<EvaluatorSDTO> data = evaluatorRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATOR_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评项目组成员数据导出并进行压缩失败：", ex);
        }
    }
    private void exportEvaluationToolData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统测评工具数据");
        try {
            List<EvaluationToolSDTO> data = evaluationToolsRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_TOOLS_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评工具数据导出并进行压缩失败：", ex);
        }
    }

    private void exportPasswordServerData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统密码服务数据");
        try {
            List<PasswordServerSDTO> data = passwordServerRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.PASSWORD_SERVER_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统密码服务数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSecurityThreatData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统安全威胁数据");
        try {
            List<SecurityThreatSDTO> data = securityThreatRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.SECURITY_THREAT_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统安全威胁标数据导出并进行压缩失败：", ex);
        }
    }

    private void exportPersonnelData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统人员数据");
        try {
            List<PersonnelSDTO> data = personnelRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.PERSONNEL_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统人员数据导出并进行压缩失败：", ex);
        }
    }

    private void exportSecurityDocumentData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.3, "导出系统安全管理文档数据");
        try {
            List<SecurityDocumentSDTO> data = securityDocumentRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.SECURITY_DOCUMENT_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统安全管理文档数据导出并进行压缩失败：", ex);
        }
    }

    private void exportAssetData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.4, "导出系统资产数据");
        try {
            List<AssetSDTO> data = assetRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.ASSET_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统资产数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationDescData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.4, "导出系统资产测评说明数据");
        try {
            List<EvaluationDescSDTO> data = evaluationDescRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationDescDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_DESC_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统资产测评说明数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationMethodData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.4, "导出系统资产测评方式数据");
        try {
            List<EvaluationMethodSDTO> data = evaluationMethodRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationMethodDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_METHOD_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统资产测评方式数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationRequireData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.4, "导出系统测评配合需求数据");
        try {
            List<EvaluationRequireSDTO> data = evaluationRequireRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_REQUIRE_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统资产测评配合需求数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationRecordData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.4, "导出系统现场测评记录数据");
        try {
            List<EvaluationRecordSDTO> data = evaluationRecordRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationRecordDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_RECORD_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统现场测评记录数据导出并进行压缩失败：", ex);
        }
    }

    private void exportUnitEvaluationData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.5, "导出系统单元测评数据");
        try {
            List<UnitEvaluationSDTO> data = unitEvaluationRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customUnitEvaluationDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.UNIT_EVALUATION_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统单元测评数据导出并进行压缩失败：", ex);
        }
    }

    private void exportLayerEvaluationData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.5, "导出系统层面测评数据");
        try {
            List<LayerEvaluationSDTO> data = layerEvaluationRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customLayerEvaluationDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.LAYER_EVALUATION_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统层面测评数据导出并进行压缩失败：", ex);
        }
    }

    private void exportOverallEvaluationData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.5, "导出系统总体评价数据");
        try {
            List<OverallEvaluationSDTO> data = overallEvaluationRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customOverallEvaluationDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.OVERALL_EVALUATION_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统总体评价数据导出并进行压缩失败：", ex);
        }
    }

    private void exportResultCorrectionData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.6, "导出系统结果修正数据");
        try {
            List<ResultCorrectionSDTO> data = resultCorrectionRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customResultCorrectionDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.RESULT_CORRECTION_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统结果修正数据导出并进行压缩失败：", ex);
        }
    }

    private void exportRiskAnalysisData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.6, "导出系统风险分析数据");
        try {
            var data = riskAnalysisRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customUnitRiskAnalysisDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.UNIT_RISK_ANALYSIS_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统结果风险分析导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluatorQualificationData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.6, "导出密评人员资格情况数据");
        try {
            var data = evaluatorQualificationRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.PROOF_EVALUATOR.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("密评人员资格情况数据导出并进行压缩失败：", ex);
        }
    }

    private void exportEvaluationReportData(SystemSDTO systemSDTO, ZipOutputStream zOut) {
        processNotify(0.7, "导出系统测评报告数据");
        try {
            List<EvaluationReportSDTO> data = evaluationReportRepository.findAllBySystemId(systemSDTO.getId())
                    .stream()
                    .map(SystemExportMapper.INSTANCE::toStandardDTO)
                    .filter(DistinctUtils.customEvaluationReportDistinct())
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(data)) {
                zOut.putNextEntry(new ZipEntry(StandardInfo.EVALUATION_REPORT_FILE.getValue()));
                zOut.write(generateFileStreamData(JsonUtils.toJson(data)));
            }
        } catch (IOException ex) {
            throw new RuntimeException("系统测评报告数据导出并进行压缩失败：", ex);
        }
    }


    private byte[] generateFileStreamData(String content) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        IOUtils.write(content, bos, StandardCharsets.UTF_8);
        return bos.toByteArray();
    }

    private void processNotify(double value, String tip) {
        if (Objects.nonNull(processCallback)) {
            processCallback.process(value, tip);
        }
    }
}
